#include "stdafx.h"
#include "EffectObj.h"

EffectObj::EffectObj(string strName, PD3D12Device pDevice, DXGI_FORMAT backBufferFormat, DXGI_FORMAT depthStencilFormat, bool msaaState, UINT msaaQuality):NameObjBase(strName)
{
	m_pDevice = pDevice;
	m_BackBufferFormat = backBufferFormat;
	m_DepthStencilFormat = depthStencilFormat;
	m_4xMsaaState = msaaState;
	m_4xMsaaQuality = msaaQuality;
}




EffectObj::~EffectObj()
{
}

std::vector<CD3DX12_STATIC_SAMPLER_DESC> EffectObj::GetStaticSamplers()
{
	// Applications usually only need a handful of samplers.  So just define them all up front
	// and keep them available as part of the root signature.  

	CD3DX12_STATIC_SAMPLER_DESC pointWrap(
		0, // shaderRegister
		D3D12_FILTER_MIN_MAG_MIP_POINT, // filter
		D3D12_TEXTURE_ADDRESS_MODE_WRAP,  // addressU
		D3D12_TEXTURE_ADDRESS_MODE_WRAP,  // addressV
		D3D12_TEXTURE_ADDRESS_MODE_WRAP); // addressW

	CD3DX12_STATIC_SAMPLER_DESC pointClamp(
		1, // shaderRegister
		D3D12_FILTER_MIN_MAG_MIP_POINT, // filter
		D3D12_TEXTURE_ADDRESS_MODE_CLAMP,  // addressU
		D3D12_TEXTURE_ADDRESS_MODE_CLAMP,  // addressV
		D3D12_TEXTURE_ADDRESS_MODE_CLAMP); // addressW

	CD3DX12_STATIC_SAMPLER_DESC linearWrap(
		2, // shaderRegister
		D3D12_FILTER_MIN_MAG_MIP_LINEAR, // filter
		D3D12_TEXTURE_ADDRESS_MODE_WRAP,  // addressU
		D3D12_TEXTURE_ADDRESS_MODE_WRAP,  // addressV
		D3D12_TEXTURE_ADDRESS_MODE_WRAP); // addressW

	CD3DX12_STATIC_SAMPLER_DESC linearClamp(
		3, // shaderRegister
		D3D12_FILTER_MIN_MAG_MIP_LINEAR, // filter
		D3D12_TEXTURE_ADDRESS_MODE_CLAMP,  // addressU
		D3D12_TEXTURE_ADDRESS_MODE_CLAMP,  // addressV
		D3D12_TEXTURE_ADDRESS_MODE_CLAMP); // addressW

	CD3DX12_STATIC_SAMPLER_DESC anisotropicWrap(
		4, // shaderRegister
		D3D12_FILTER_ANISOTROPIC, // filter
		D3D12_TEXTURE_ADDRESS_MODE_WRAP,  // addressU
		D3D12_TEXTURE_ADDRESS_MODE_WRAP,  // addressV
		D3D12_TEXTURE_ADDRESS_MODE_WRAP,  // addressW
		0.0f,                             // mipLODBias
		8);                               // maxAnisotropy

	CD3DX12_STATIC_SAMPLER_DESC anisotropicClamp(
		5, // shaderRegister
		D3D12_FILTER_ANISOTROPIC, // filter
		D3D12_TEXTURE_ADDRESS_MODE_CLAMP,  // addressU
		D3D12_TEXTURE_ADDRESS_MODE_CLAMP,  // addressV
		D3D12_TEXTURE_ADDRESS_MODE_CLAMP,  // addressW
		0.0f,                              // mipLODBias
		8);                                // maxAnisotropy

	 CD3DX12_STATIC_SAMPLER_DESC shadow(
		6, // shaderRegister
		D3D12_FILTER_COMPARISON_MIN_MAG_LINEAR_MIP_POINT, // filter
		D3D12_TEXTURE_ADDRESS_MODE_BORDER,  // addressU
		D3D12_TEXTURE_ADDRESS_MODE_BORDER,  // addressV
		D3D12_TEXTURE_ADDRESS_MODE_BORDER,  // addressW
		0.0f,                               // mipLODBias
		16,                                 // maxAnisotropy
		D3D12_COMPARISON_FUNC_LESS_EQUAL,
		D3D12_STATIC_BORDER_COLOR_OPAQUE_BLACK);

	 vector< CD3DX12_STATIC_SAMPLER_DESC> ret={
		pointWrap, pointClamp,
		linearWrap, linearClamp,
		anisotropicWrap, anisotropicClamp,
		shadow
	};
	 return ret;
}

void EffectObj::InitRootSign()
{
	CD3DX12_DESCRIPTOR_RANGE texTable0;
	texTable0.Init(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 1, 0, 0);

	CD3DX12_DESCRIPTOR_RANGE texTable1;
	texTable1.Init(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 48, 1, 0);

	// Root parameter can be a table, root descriptor or root constants.
	vector<CD3DX12_ROOT_PARAMETER> slotRootParameter(FrameResourceObj::TYPE_COUNT);

	// Perfomance TIP: Order from most frequent to least frequent.
	slotRootParameter[FrameResourceObj::TYPE_OBJ_BUFFER].InitAsConstantBufferView(0);
	slotRootParameter[FrameResourceObj::TYPE_OBJ_SKIN_ANIMATION_BUFFER].InitAsConstantBufferView(1);
	slotRootParameter[FrameResourceObj::TYPE_GLOBAL_DATA].InitAsConstantBufferView(2);
	slotRootParameter[FrameResourceObj::TYPE_LIGHT_DATA].InitAsConstantBufferView(3);//TYPE_LIGHT_DATA
	slotRootParameter[FrameResourceObj::TYPE_MATERIAL_DATA].InitAsShaderResourceView(0, 1);//TYPE_MATERIAL_DATA
	slotRootParameter[FrameResourceObj::TYPE_TEXTURE_CUBE].InitAsDescriptorTable(1, &texTable0, D3D12_SHADER_VISIBILITY_PIXEL);//TYPE_TEXTURE_CUBE
	slotRootParameter[FrameResourceObj::TYPE_TEXTURE_2D].InitAsDescriptorTable(1, &texTable1, D3D12_SHADER_VISIBILITY_PIXEL);//TYPE_TEXTURE_2D

	auto staticSamplers = GetStaticSamplers();

	// A root signature is an array of root parameters.
	CD3DX12_ROOT_SIGNATURE_DESC rootSigDesc(slotRootParameter.size(), slotRootParameter.data(),
		(UINT)staticSamplers.size(), staticSamplers.data(),
		D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT);

	// create a root signature with a single slot which points to a descriptor range consisting of a single constant buffer
	ComPtr<ID3DBlob> serializedRootSig = nullptr;
	ComPtr<ID3DBlob> errorBlob = nullptr;
	HRESULT hr = D3D12SerializeRootSignature(&rootSigDesc, D3D_ROOT_SIGNATURE_VERSION_1,
		serializedRootSig.GetAddressOf(), errorBlob.GetAddressOf());

	if (errorBlob != nullptr)
	{
		::OutputDebugStringA((char*)errorBlob->GetBufferPointer());
	}
	ThrowIfFailed(hr);

	ThrowIfFailed(m_pDevice->CreateRootSignature(
		0,
		serializedRootSig->GetBufferPointer(),
		serializedRootSig->GetBufferSize(),
		IID_PPV_ARGS(m_RootSignature.GetAddressOf())));
}



void EffectObj::UpdateFrameResource(PCommandList pCommandList, shared_ptr<FrameResourceObj> pResObj)
{
	m_pFrameRes = pResObj;
	m_pFrameRes->BindResource();
	
}

void EffectObj::UpdateShader(const vector<string>& vShaderName)
{
	try
	{
		unordered_set<string> vTexName;
		vector<suShader> vShader;
		for (string s : vShaderName)
		{
			vShader.push_back(ShaderManage::GetInstance()->Get(s));
		}

		for (suShader shader : vShader)
		{
			if (m_vPipe.find(shader.GetName()) == m_vPipe.end() && IsSupportInputType(shader.GetInputType()))
			{
				ComPtr<ID3D12PipelineState> pPipe;
				vector<D3D12_INPUT_ELEMENT_DESC> vInputLayout = shader.GetInputDes();

				D3D12_GRAPHICS_PIPELINE_STATE_DESC opaquePsoDesc;
				ZeroMemory(&opaquePsoDesc, sizeof(D3D12_GRAPHICS_PIPELINE_STATE_DESC));
				opaquePsoDesc.InputLayout = { vInputLayout.data(), (UINT)vInputLayout.size() };
				opaquePsoDesc.pRootSignature = m_RootSignature.Get();


				{
					D3D12_SHADER_BYTECODE* vShaderRes[] =
					{
						&opaquePsoDesc.VS,
						&opaquePsoDesc.HS,
						&opaquePsoDesc.DS,
						&opaquePsoDesc.GS,
						&opaquePsoDesc.PS,
					};
					for (int i = 0; i < suShader::TYPE_MAX - 1; ++i)
					{
						Microsoft::WRL::ComPtr<ID3DBlob> pShader = shader.GetCompileShader((suShader::emShaderType)i);
						if (pShader != nullptr)
						{
							*(vShaderRes[i]) = {
								reinterpret_cast<BYTE*>(pShader->GetBufferPointer()),
								pShader->GetBufferSize()
							};
						}
					}
				}
				opaquePsoDesc.RasterizerState = CD3DX12_RASTERIZER_DESC(D3D12_DEFAULT);
				opaquePsoDesc.BlendState = CD3DX12_BLEND_DESC(D3D12_DEFAULT);
				opaquePsoDesc.DepthStencilState = CD3DX12_DEPTH_STENCIL_DESC(D3D12_DEFAULT);
				opaquePsoDesc.SampleMask = UINT_MAX;
				opaquePsoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
				opaquePsoDesc.NumRenderTargets = 1;
				opaquePsoDesc.RTVFormats[0] = m_BackBufferFormat;
				opaquePsoDesc.SampleDesc.Count = m_4xMsaaState ? 4 : 1;
				opaquePsoDesc.SampleDesc.Quality = m_4xMsaaState ? (m_4xMsaaQuality - 1) : 0;
				opaquePsoDesc.DSVFormat = m_DepthStencilFormat;
				HRESULT hr = (m_pDevice->CreateGraphicsPipelineState(&opaquePsoDesc, IID_PPV_ARGS(&pPipe)));
				ThrowIfFailed(hr);
				m_vPipe[shader.GetName()] = pPipe;
			}
		}
	}
	catch (const DxException& e)
	{
		assert(false);
		std::wstring sErr = e.ToString();
		sErr = sErr;
	}

}
